1 /*
2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021
3 License:   [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License].
4 Authors: Marcelo S. N. Mancini
5 
6 	Copyright Marcelo S. N. Mancini 2018 - 2021.
7 Distributed under the CC BY-4.0 License.
8    (See accompanying file LICENSE.txt or copy at
9 	https://creativecommons.org/licenses/by/4.0/
10 */
11 module hip.console.console;
12 import hip.config.opts;
13 import hip.util.string : BigString, String;
14 import hip.util.format;
15 
16 
17 enum Platforms
18 {
19     default_,
20     desktop,
21     android,
22     uwp,
23     wasm,
24     psvita,
25     appleos,
26     null_
27 }
28 static enum androidTag = "HipremeEngine";
29 enum GUI_CONSOLE = true;
30 
31 ///If it is inside thread local storage, then, it won't work being called from another thread
32 @nogc __gshared void function(string toPrint) _log;
33 @nogc __gshared void function(string toPrint) _info;
34 @nogc __gshared void function(string toPrint) _warn;
35 @nogc __gshared void function(string toPrint) _err;
36 @nogc __gshared void function(string toPrint) _fatal;
37 version(PSVita) extern(C) void hipVitaPrint(uint length, const(char)* str) @nogc;
38 
39 version(UWP){}
40 else version(Windows)
41     version = WindowsNative;
42 
43 
44 enum WindowsConsoleColors
45 {
46     lightBlue = 1,
47     darkGreen = 2,
48     darkTeal = 3,
49     lightRed = 4,
50     pink = 5,
51     yellow = 6,
52     lightGrey = 7,
53     grey = 8,
54     blue = 9,
55     green = 10,
56     lightTeal = 11,
57     red = 12,
58     white = 15
59 }
60 
61 class Console
62 {
63     string name;
64     string[] lines;
65 
66     __gshared ushort idCount = 0;
67     ushort id;
68 
69     private uint logCounter = 0;
70     __gshared Console DEFAULT;
71     
72     string indentation;
73     int indentationCount;
74     int maxLines = 255;
75     int indentationSize = 4; //? Don't know if it should be used instead of \t
76     bool useTab = true;
77     bool isShowing = true;
78     
79 
80     alias printFuncT = @nogc void function(string);
81     static void install(Platforms p = Platforms.default_, printFuncT printFunc = null)
82     {
83         DEFAULT = new Console("Output", 99);
84         version(WindowsNative)
85         {
86             import core.sys.windows.winbase;
87             import core.sys.windows.wincon;
88             static void* windowsConsole;
89             if(windowsConsole is null)
90                 windowsConsole = GetStdHandle(STD_OUTPUT_HANDLE);
91         }
92         switch(p) with(Platforms)
93         {
94             case null_:
95                 _log = function(string s){};
96                 _info = _log;
97                 _warn = _log;
98                 _err = _log;
99                 _fatal = _err;
100                 break;
101             case android:
102                 version(Android)
103                 {
104                     import hip.jni.helper.androidlog; 
105                     alias fnType = @nogc void function(string);
106                     _log   = cast(fnType)function(string s){alogi(androidTag, (s~"\0").ptr);};
107                     _info = _log;
108                     _warn  = cast(fnType)function(string s){alogw(androidTag, (s~"\0").ptr);};
109                     _err   = cast(fnType)function(string s){aloge(androidTag, (s~"\0").ptr);};
110                     _fatal = cast(fnType)function(string s){alogf(androidTag, (s~"\0").ptr);};
111                 }
112                 break;  
113             case psvita:
114             {
115                 version(PSVita)
116                 {
117                     _log = function(string s){hipVitaPrint(s.length, s.ptr);};
118                     _info = _warn = _err = _fatal = _log;
119                 }
120                 break;
121             }
122             case wasm:
123                 version(WebAssembly)
124                 {
125                     import arsd.webassembly;
126                     import std.stdio;
127                     alias nogcfn = @nogc void function(string s);
128                     _log = cast(nogcfn)function(string s){writeln(s);};
129                     _fatal = _err = cast(nogcfn)function(string s){eval(q{console.error.apply(null, arguments)}, s);};
130                     _warn = cast(nogcfn)function(string s){eval(q{console.warn.apply(null, arguments)}, s);};
131                     _info = cast(nogcfn)function(string s){eval(q{console.info.apply(null, arguments)}, s);};
132                 }
133                 break;
134             case uwp:
135                 _log = printFunc;
136                 _info = _log;
137                 _warn = _log;
138                 _err = _log;
139                 _fatal = _err;
140                 break;
141             case default_:
142             case appleos:
143             case desktop:
144             default:
145             {
146                 _log = function(string s)
147                 {
148                     version(WebAssembly) assert(false, s);
149                     else
150                     {
151                         import core.stdc.stdio;
152                         printf("%.*s\n", cast(int)s.length, s.ptr);
153                         version(PSVita){}
154                         else version(CustomRuntimeTest){}
155                         else fflush(stdout);
156                     }
157                 };
158                 _info = function(string s)
159                 {
160                     version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.blue);}
161                     _log(s);
162                     version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.white);}
163                 };
164                 _warn = function(string s)
165                 {
166                     version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.yellow);}
167                     _log(s);
168                     version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.white);}
169                 };
170                 _err = function(string s)
171                 {
172                     version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.red);}
173                     _log(s);
174                     version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.white);}
175                 };
176                 _fatal = function(string s)
177                 {
178                     version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.pink);}
179                     _log(s);
180                     version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.white);}
181                 };
182                 break;
183             }
184         }
185     }
186     private this(string consoleName, ushort id)
187     {
188         lines = new string[maxLines];
189         name = consoleName;
190         this.id = id;
191     }
192 
193     this(string consoleName)
194     {
195         lines = new string[maxLines];
196         name = consoleName;
197         id = idCount;
198         idCount++;
199     }
200 
201     private void _formatLog(ref string log)
202     {
203         log~= indentation;
204         lines[logCounter++] = log;
205         if(logCounter > maxLines)
206         {
207             lines = lines[1..$];
208             logCounter--;
209         }
210     }
211     void hipLog(string msg)
212     {
213         lines~= msg;
214         _log(lines[$-1]);
215     }
216     
217     
218     void log(string msg) @nogc
219     {
220         static if(!HE_NO_LOG && !HE_ERR_ONLY)
221         {
222             //mtx.lock();
223             _log(msg);
224             //mtx.unlock();
225         }
226     }
227 
228     void logStr(string str)
229     {
230         _info(str);
231     }
232     void info(string msg)
233     {
234         static if(!HE_NO_LOG && !HE_ERR_ONLY)
235         {
236             //mtx.lock();
237             _info(BigString("INFO: ",  msg).toString);
238             //mtx.unlock();
239         }
240     }
241 
242     void warn(string msg)
243     {
244         static if(!HE_NO_LOG && !HE_ERR_ONLY)
245         {
246             //mtx.lock();
247             _warn(BigString("WARNING: ",  msg).toString);
248             //mtx.unlock();
249         }
250     }
251     
252     void error(string msg)
253     {
254         static if(!HE_NO_LOG)
255         {
256             //mtx.lock();
257             _err(BigString("ERROR: ",  msg).toString);
258             //mtx.unlock();
259         }
260     }
261   
262     void fatal(string msg)
263     {
264         static if(!HE_NO_LOG)
265         {
266             //mtx.lock();
267             _fatal(BigString("FATAL ERROR: ", msg).toString);
268             //mtx.unlock();
269         }
270     }
271 
272     void indent()
273     {
274         //mtx.lock();
275         if(useTab)
276             indentation~= "\t";
277         else
278             for(int i = 0; i < indentationSize; i++)
279                 indentation~= " ";
280         indentationCount++;
281         //mtx.unlock();
282     }
283 
284     void unindent()
285     {
286         //mtx.lock();
287         if(useTab)
288             indentation = indentation[1..$];
289         else
290             indentation = indentation[indentationSize..$];
291         indentationCount--;
292         //mtx.unlock();
293     }
294 }